package com.holly.unit.deform.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.holly.unit.core.pojo.response.ErrorResponseData;
import com.holly.unit.db.api.exception.enums.DatabaseExceptionEnum;
import com.holly.unit.db.api.factory.PageFactory;
import com.holly.unit.db.api.factory.PageResultFactory;
import com.holly.unit.db.api.pojo.db.TableFieldInfo;
import com.holly.unit.db.api.pojo.db.TableInfo;
import com.holly.unit.db.api.pojo.druid.DruidProperties;
import com.holly.unit.db.api.pojo.page.PageResult;
import com.holly.unit.db.api.util.DatabaseUtil;
import com.holly.unit.deform.api.pojo.online.pojo.ColumnInfo;
import com.holly.unit.deform.api.pojo.online.pojo.DesignFormOnlineFieldRequest;
import com.holly.unit.deform.api.pojo.online.pojo.DesignFormOnlineIndexRequest;
import com.holly.unit.deform.api.pojo.online.pojo.DesignFormOnlineRequest;
import com.holly.unit.deform.entity.DesignFormOnline;
import com.holly.unit.deform.entity.DesignFormOnlineField;
import com.holly.unit.deform.entity.DesignFormOnlineIndex;
import com.holly.unit.deform.mapper.DesignFormOnlineMapper;
import com.holly.unit.deform.util.DatabaseDeFormUtil;
import com.holly.unit.deform.util.DbTypeUtil;
import com.holly.unit.deform.util.JsonUtil;
import com.holly.unit.jwt.api.exception.JwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


@Service
public class DesignFormOnlineService extends ServiceImpl<DesignFormOnlineMapper, DesignFormOnline> {

    @Autowired
    private DesignFormOnlineFieldService fieldService;

    @Autowired
    private DesignFormOnlineIndexService indexService;

    @Resource
    private DruidProperties druidProperties;

    public PageResult<DesignFormOnline> queryPageList(DesignFormOnlineRequest designFormOnlineDTO) {
        LambdaQueryWrapper<DesignFormOnline> wrapper = createWrapper(designFormOnlineDTO);
        Page<DesignFormOnline> page = this.page(PageFactory.defaultPage(), wrapper);
        return PageResultFactory.createPageResult(page);
    }

    public List<TableInfo> queryPageListFrom() {
        return DatabaseUtil.selectTables(druidProperties);
    }

    /**
     * 创建wrapper
     *
     * @author holly
     * @date 2020/11/6 10:16
     */
    private LambdaQueryWrapper<DesignFormOnline> createWrapper(DesignFormOnlineRequest designFormOnlineDTO) {
        LambdaQueryWrapper<DesignFormOnline> queryWrapper = new LambdaQueryWrapper<>();

        // 根据表名称模糊查询
        queryWrapper.like(StrUtil.isNotEmpty(designFormOnlineDTO.getTableName()), DesignFormOnline::getTableName, designFormOnlineDTO.getTableName());
        // 根据表描述模糊查询
        queryWrapper.like(StrUtil.isNotEmpty(designFormOnlineDTO.getTableTxt()), DesignFormOnline::getTableTxt, designFormOnlineDTO.getTableTxt());

        return queryWrapper;
    }

    @Transactional(rollbackFor = Exception.class)
    public void add(DesignFormOnlineRequest designFormOnlineDTO){
        String tableName = designFormOnlineDTO.getTableName();
        List<TableFieldInfo> tableInfos = DatabaseUtil.getTableFields(druidProperties, tableName);
        if(tableInfos.size() > 0) {
            throw new JwtException(DatabaseExceptionEnum.FIELD_GET_ERROR,tableName);
        }
        String uuid = IdUtil.simpleUUID();
        designFormOnlineDTO.setId(uuid);
        DesignFormOnline designFormOnline = new DesignFormOnline();
        BeanUtil.copyProperties(designFormOnlineDTO, designFormOnline);
        this.save(designFormOnline);

        List<DesignFormOnlineField> fieldList = new ArrayList<>();
        List<DesignFormOnlineFieldRequest> fields = designFormOnlineDTO.getFields();
        for (int i = 0; i < fields.size(); i++) {
            DesignFormOnlineFieldRequest field = fields.get(i);
            field.setId(null);
            field.setCgformHeadId(uuid);
            if (field.getOrderNum() == null) {
                field.setOrderNum(i);
            }
            specialFieldHandler(field);
            DesignFormOnlineField onlineField = new DesignFormOnlineField();
            BeanUtil.copyProperties(field, onlineField);
            fieldList.add(onlineField);
        }
        fieldService.saveBatch(fieldList);

        //组装sql语句
        String sql = DbTypeUtil.createSQL(fieldList,tableName,designFormOnlineDTO.getTableTxt());
        DatabaseUtil.createDataTable(druidProperties,sql);

        List<DesignFormOnlineIndexRequest> indexs = designFormOnlineDTO.getIndexs();
        if(indexs != null && indexs.size() > 0){
            List<DesignFormOnlineIndex> indexList = new ArrayList<>();
            for (DesignFormOnlineIndexRequest index : indexs) {
                index.setId(null);
                index.setCgformHeadId(uuid);

                DesignFormOnlineIndex onlineIndex = new DesignFormOnlineIndex();
                BeanUtil.copyProperties(index, onlineIndex);
                indexList.add(onlineIndex);
            }
            indexService.saveBatch(indexList);
            //处理完表 再处理索引
            DatabaseUtil.executeDDL(druidProperties,DbTypeUtil.createIndex(tableName,indexList));
        }
    }

    /**
     * 保存编辑online表单字段的时候需要作些特殊处理
     * @param field
     */
    private void specialFieldHandler(DesignFormOnlineFieldRequest field){
        if("Text".equals(field.getDbType())||"Blob".equals(field.getDbType())){
            field.setDbLength(0);
            field.setDbPointLength(0);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateDesignForm(DesignFormOnlineRequest designFormOnlineDTO) {
        //表基础信息
        DesignFormOnline headEntity = super.getById(designFormOnlineDTO.getId());
        if(headEntity == null){
            new ErrorResponseData("199","未找到对应实体");
        }
        // table version 自增1
        Integer version = headEntity.getTableVersion();
        if (version == null) {
            version = 1;
        }
        designFormOnlineDTO.setTableVersion(++version);

        DesignFormOnline online = new DesignFormOnline();
        BeanUtil.copyProperties(designFormOnlineDTO, online);
        this.updateById(online);

        //表字段
        List<DesignFormOnlineFieldRequest> fields = designFormOnlineDTO.getFields();
        List<DesignFormOnlineField> addFields = new ArrayList<>();
        for (DesignFormOnlineFieldRequest field : fields) {
            DesignFormOnlineField onlineIndex = new DesignFormOnlineField();
            BeanUtil.copyProperties(field, onlineIndex);
            specialFieldHandler(field);
            onlineIndex.setCgformHeadId(designFormOnlineDTO.getId());
            addFields.add(onlineIndex);
        }
        //先删除
        fieldService.remove(new LambdaQueryWrapper<DesignFormOnlineField>().eq(DesignFormOnlineField::getCgformHeadId,designFormOnlineDTO.getId()));
        //批量新增
        fieldService.saveBatch(addFields);

        //索引
        //先删除
        indexService.remove(new LambdaQueryWrapper<DesignFormOnlineIndex>().eq(DesignFormOnlineIndex::getCgformHeadId,designFormOnlineDTO.getId()));
        List<DesignFormOnlineIndexRequest> indexs = designFormOnlineDTO.getIndexs();
        if(indexs != null && indexs.size() > 0){
            // 将fields分类成 添加和修改 两个列表
            List<DesignFormOnlineIndex> addindexs = new ArrayList<>();
            for (DesignFormOnlineIndexRequest inde : indexs) {
                DesignFormOnlineIndex onlineIndex = new DesignFormOnlineIndex();
                BeanUtil.copyProperties(inde, onlineIndex);
                if (StrUtil.isEmpty(inde.getId())) {
                    //批量修改
                    indexService.updateById(onlineIndex);
                } else {
                    // 新增项
                    onlineIndex.setCgformHeadId(designFormOnlineDTO.getId());
                    addindexs.add(onlineIndex);
                }
            }
            //批量新增
            indexService.saveBatch(addindexs);
        }
        //修改数据库表字段
        DatabaseUtil.executeDDL(druidProperties,this.updateTable(addFields,online));
    }

    private List<String> updateTable(List<DesignFormOnlineField> fields,DesignFormOnline online) {
        String alterSql = "alter table  "+online.getTableName()+" ";
        List<String> alterList = new ArrayList<>();
        List<String> keyList = new ArrayList<>();
        try {
            //查询表字段信息
            List<ColumnInfo> originalTableColumn = DatabaseDeFormUtil.findOriginalTableColumn(druidProperties, online.getTableName());
            Map<String, ColumnInfo> maps = originalTableColumn.stream().collect(Collectors.toMap(ColumnInfo::getFieldName, Function.identity()));
            //前端传过来修改字段信息
            Map<String,ColumnInfo> dataTable = getConfigColumns(fields);
            for (String columnName : dataTable.keySet()) {
                ColumnInfo cgFormColumnMeta = dataTable.get(columnName);
                //遍历配置表 判断原表列是否包含当前列
                if(!maps.containsKey(columnName)){
                    //表如果不存在该列，则要对表做修改、增加、删除该列动作 此处无法处理删除的列，因为在这个循环中无法获得该列
                    alterList.add(alterSql+ JsonUtil.getAddColumnSql(cgFormColumnMeta));
                }else {
                    //已经存在,判断是否类型、是否为空、字段备注,如果有修改则处理修改
                    ColumnInfo dataColumnMeta = maps.get(columnName);
                    //如果不相同，则表示有变化，则需要修改
                    if (!dataColumnMeta.equalsByDataType(cgFormColumnMeta)) {
                        alterList.add(alterSql+JsonUtil.getUpdateColumnSql(cgFormColumnMeta));
                    }
                }
                //判断是否是主键
                if(cgFormColumnMeta.getDbIsKey() == 1){
                    keyList.add(DbTypeUtil.judgeNumber(cgFormColumnMeta.getFieldName()));
                }
            }
            //删除数据库的列
            for (String columnName : maps.keySet()) {
                if (!dataTable.containsKey(columnName)) {
                    alterList.add(alterSql+JsonUtil.getDropColumnSql(columnName));
                }
            }
            if(keyList != null && keyList.size() > 0){
                alterList.add(alterSql+"DROP PRIMARY KEY ,ADD PRIMARY KEY ("+ String.join(",",keyList)+");");
            }
            return alterList;
        } catch (Exception e1) {
            throw new RuntimeException();
        }
    }

    /**
     * 获取cgform配置表数据列
     * @return
     */
    private Map<String, ColumnInfo> getConfigColumns(List<DesignFormOnlineField> fieldList){
        Map<String, ColumnInfo> columnMap = new HashMap<String, ColumnInfo>();
        ColumnInfo columnInfo;
        for (DesignFormOnlineField field : fieldList) {
            columnInfo = new ColumnInfo();
            columnInfo.setColName(field.getDbFieldName());
            String dataType = field.getDbType();
            if (dataType.contains("string")) {
                dataType = "varchar("+field.getDbLength()+")";
            } else if (dataType.contains("Date")) {
                dataType = "datetime";
            } else if (dataType.contains("Text")) {
                dataType = "text";
            } else if (dataType.contains("Blob")) {
                dataType = "blob";
            } else if (dataType.contains("double")) {
                dataType = "double("+field.getDbLength()+","+field.getDbPointLength()+")";
            } else if (dataType.contains("int")) {
                dataType = "int("+field.getDbLength()+")";
            } else if (dataType.contains("BigDecimal")) {
                dataType = "decimal("+field.getDbLength()+","+field.getDbPointLength()+")";
            }
            columnInfo.setColType(dataType);
            columnInfo.setNullAble(field.getDbIsNull()==1?0:1);
            columnInfo.setDbIsKey(field.getDbIsKey());
            columnInfo.setFieldName(field.getDbFieldName());
            columnInfo.setColComment(field.getDbFieldTxt());
            columnInfo.setDbDefaultVal(field.getDbDefaultVal());
            columnMap.put(field.getDbFieldName().toLowerCase(), columnInfo);

        }
        return columnMap;
    }

    public List<ColumnInfo> listByHeadId(String cgformCode) {
        return  DatabaseDeFormUtil.findOriginalTableColumn(druidProperties,cgformCode);
    }

    public void deleteTable(String id, String tableName) {
        //删除自定义表
        LambdaQueryWrapper<DesignFormOnline> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DesignFormOnline::getId, id);
        this.remove(queryWrapper);
        //删除自定义表字段
        LambdaQueryWrapper<DesignFormOnlineField> queryFieldWrapper = new LambdaQueryWrapper<>();
        queryFieldWrapper.eq(DesignFormOnlineField::getCgformHeadId, id);
        fieldService.remove(queryFieldWrapper);
        //删除自定义表索引
        LambdaQueryWrapper<DesignFormOnlineIndex> queryIndexWrapper = new LambdaQueryWrapper<>();
        queryIndexWrapper.eq(DesignFormOnlineIndex::getCgformHeadId, id);
        indexService.remove(queryIndexWrapper);
        //删除数据库表
        List<String> buffer = new ArrayList<>();
        buffer.add("drop table "+tableName);
        DatabaseUtil.executeDDL(druidProperties,buffer);
    }
}
